#include<at89c51ed2.h>
#include<stdio.h>
#include<mcs51reg.h>
#include<stdlib.h>
#include<string.h>
#include "io.h"
#include "graphics.h"
#include "eeprom.h"

/**************************************************************************/

#define CommandWrite 			0xF01C
#define ColumnSelect_0_63 		0xF014
#define ColumnSelect_64_128 	0xF018
#define DDRAM_0_63 				0xF015
#define DDRAM_64_128 			0xF019
#define	StatusRead				0xF01E
#define readLCD_RIGHT		 	0xF017
#define readLCD_LEFT		 	0xF01B
#define MAX_COL_PIXEL			128		//MAX_COL_PIXEL the physical matrix width (x direction)
#define PAGE_OFFSET				0xB8
#define Y_OFFSET				0x40
#define characterWidth			3
#define x_graphStart			8
#define maxY					 56
/******************************************************************************/



/********************************************************************************/
void glcdData(char val,int reg)__critical
{	
	/*GLCD Command Write*/
	if(reg==0){
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)CommandWrite ; //assigning specific address 0xFFFF to pointer
	*test=val;//debug data value 
	}
	/*GLCD Column Selection from 0-63*/
	if(reg==1){
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)ColumnSelect_0_63; //assigning specific address 0xFFFF to pointer
	*test=val;//debug data value 
	}
	
	/*GLCD Column Selection from 64-128*/
	if(reg==2){
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)ColumnSelect_64_128; //assigning specific address 0xFFFF to pointer
	*test=val;//debug data value 
	}
	
	/*GLCd DDRAM Write column 0-63*/
	if(reg==3){
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)DDRAM_0_63; //assigning specific address 0xFFFF to pointer
	*test=val;//debug data value 
	}
	
	/*GLCD DDRAM Write column 63-128*/ 
	if(reg==4){
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)DDRAM_64_128; //assigning specific address 0xFFFF to pointer
	*test=val;//debug data value 
	}
	


}



char gLCD_read(int side)__critical{
	
	char val;
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	if(side==1) //left side of screen
	{
	test=(xdata char*)readLCD_LEFT	; //assigning specific address 0xFFFF to pointer
	}
	else if(side==2)
	{
	test=(xdata char*)readLCD_RIGHT	; //assigning specific address 0xFFFF to pointer
	}
	
	val=*test;//debug data value 
	return val;
}


void glcddelay(int time){
	int i;
	for(i=0;i<time+1;i++){
	}
}	

void gLCD_busy()__critical{
	
	char val;
	
	xdata char volatile *test;   //pointer pointing to an address in xdata space 
	test=(xdata char*)StatusRead; //assigning specific address 0xFFFF to pointer
	val=*test;//debug data value 
	
	val&=0x80;
	while(val!=0x00)
	{
		glcddelay(10);
		test=(xdata char*)StatusRead; //assigning specific address 0xFFFF to pointer
		val=*test;//debug data value 
		val&=0x80;
		printf("GLCD Busy \n\r");
	}
}





void glcd_init()__critical
{
	
	/*reset to low and high*/
	//glcddelay(100);		//software delay
	 P3_2=0;
	glcddelay(400);
	 P3_2=1;
	
	
	
	glcddelay(100);
	
	glcdData(0xB8,0);/*select first page*/
	
	glcddelay(100);
	
	glcdData(0x40,0);/*select row 0*/
	
	glcddelay(100);
	
	glcdData(0x3f,0);/*display on*/
	
	glcddelay(100);
	
}
		
		
		
		
		
		
		/*
*********************************************************************************************************
*                         		WRITE A SINGLE BYTE AT A COLUMN# AND PAGE#
*
* Description : This function writes a single byte 'c' to a column position defined by 'col' and 
*				to PAGE# indicated by the variable 'page'
* Arguments   : 'col'		the column position (0-127) of the LCD, 0<=col<128 (MAX_COL_PIXEL in ks0108.h)
*				'page'		the PAGE number (0-7) of the LCD. It is NOT the y coordinate as our usual 
*							Cartesian coordinate system. 
*							It is the PAGE number defined in JHD12864J data sheet
*				'c'			byte to write
* Returns     : none
* Notes		  : This function should has been declared as a local function because it is rarely
*				called in main. However, if we want to make a different version of string display with
*				higher efficiency, we may make use of this function to write byte in vertical manner.
*********************************************************************************************************
*/

void glcdWrByte(int col, int page,char c)__critical
{
	int chip_select;  
	

	if(col<(MAX_COL_PIXEL/2)) //decides whether to use the right or left controller
		{
			chip_select=4; //if col is between 0-63 it is left controller, else it is right controller
			}
	else
		{
			chip_select=3;
			col=col-(MAX_COL_PIXEL/2); //subtract by 64, to convert to range of 0-63 for right controller
			}
	
	glcdData(PAGE_OFFSET|page,0);
	gLCD_busy();
	glcdData(Y_OFFSET|col,0);
	gLCD_busy();
	glcdData(c,chip_select);
	
}

/*
*********************************************************************************************************
*                         					CLEAR DISPLAY
*
* Description : This function writes a fixed byte to all pages (0-7) of both half. If the byte is 0x00,
*				the action is equivalent to clearing the display (turning all pixels OFF)
* Arguments   : 'pat' 	is the pattern to write to the display in a repetitive manner. Writing 0xFF
*						for example, will turn all pixels BLACK.
*				
* Returns     : none
* Notes		  : This function makes use of GdispWrByte() thus the speed of clearing is fast!
*********************************************************************************************************
*/
void glcd_clr(char pattern)
{
	unsigned char col, page;

	for(col=0;col<128;col++)
	{
		for(page=0;page<8;page++) 
		glcdWrByte(col,page,pattern);
	}
}





void glcd_gotoaddr(int col, int page)__critical
{
	int chip_select;  
	

	if(col<(MAX_COL_PIXEL/2))
		{
			chip_select=4;
			}
	else
		{
			chip_select=3;
			col=col-(MAX_COL_PIXEL/2);
			}
	
	glcdData(PAGE_OFFSET|page,0);
	gLCD_busy();
	glcdData(Y_OFFSET|col,0);
	gLCD_busy();
	
	
}


/*
*********************************************************************************************************
*                         				SET PIXEL AT x, y POSITION
*
* Description : This function sets a pixel with color = BLACK / WHITE (defined in ks0108.h) at a position
*				defined by (x,y) following Cartesian coordinate system. Coordinates (0,0) at the 
*				top left corner, coordinates (127,63) at the lower right corner of the LCD screen.
*
* Arguments   : 'x'    0....MAX_COL_PIXEL-1 is matrix position in horizontal direction
*				'y'    0....MAX_ROW_PIXEL-1 is matrix position in vertical direction 
*				'color'  sets BLACK / WHITE standing for pixel ON/OFF
* Returns     : none
* Notes		  : The action GDispRd() has an effect of auto-increment on the x-direction (Y address)
*				Thus, GDispWr(CMD,Y_OFFSET|x) has to be immediate above data write code line
*				(color==BLACK)? GDispWr(DAT,pre_data|(1<<y%8)):GDispWr(DAT,pre_data&~(1<<y%8))
*				Data type 'bit' is Keil C specific
*********************************************************************************************************
*/



void glcd_setPixel(int x, int y)__critical
{	
	char currentData; 
	unsigned char pixelAddr;
	unsigned char page;
	unsigned char col;
	char LCDdata;
	
	
	/*calculate which page*/
	page=y/8;
	col=x;
	
	/*calculate the horizontal address of the particular pixel*/
	 pixelAddr=y%8;
	
	glcd_gotoaddr(col,page);
	
	if(col<(MAX_COL_PIXEL/2))
	{
		/*left side of screen*/
	currentData=gLCD_read(1); //dummy read, mention in the report
	currentData=gLCD_read(1);
	}
	else
	{
		/*right side of screen*/
		currentData=gLCD_read(2); //dummy read, mention in the report
		currentData=gLCD_read(2);
	}
		
	LCDdata=0x01;
	LCDdata=LCDdata<<pixelAddr;
	currentData|=LCDdata;

	
	glcdWrByte(col,page,currentData);

	
}



void glcd_clrPixel(int x, int y)__critical
{	
	char currentData; 
	unsigned char pixelAddr;
	unsigned char page;
	unsigned char col;
	int i;
	char LCDdata;
	int masker;
	unsigned char firstBit;
	
	
	/*calculate which page*/
	page=y/8;
	col=x;
	
	/*calculate the horizontal address of the particular pixel*/
	 pixelAddr=y%8;
	
	glcd_gotoaddr(col,page);
	
	if(col<(MAX_COL_PIXEL/2))
	{
		/*left side of screen*/
	currentData=gLCD_read(1); //dummy read, mention in the report
	currentData=gLCD_read(1);
	}
	else
	{
		/*right side of screen*/
		currentData=gLCD_read(2); //dummy read, mention in the report
		currentData=gLCD_read(2);
	}
	
		
		LCDdata=0xFE;		
		i=0;
		masker=0xFF;
		while(i<pixelAddr){

		firstBit=(masker&LCDdata)>>7;

		LCDdata=((LCDdata<<1)&masker)|firstBit;
	
		i++;
		}
	currentData&=LCDdata;
	
	glcdWrByte(col,page,currentData);

	
}



/*must use clrPixel- clr block of 5x1*/
void clrBlock(int col,int page)
{
int i;
unsigned char first_pixelPage;
unsigned char bottom_pixel;



first_pixelPage=page*8;
bottom_pixel=first_pixelPage+7;
for(i=0;i<5;i++)
{
glcd_clrPixel(col,bottom_pixel);
bottom_pixel--;	
}

}


/*y: 0-63, startCol: 0-127, num: 1-128*/
void drawHorzLine(int y,int startCol,int num)
	{
		unsigned char i;
		
		for(i=0;i<num;i++){
			
			glcd_setPixel(startCol,y);
			startCol++;
		
//			if(startCol==128){
//				break;
//			}

		}
	}
	



/*x 0-127, startRow: 0-63, num=number of pixels=1-64*/
void drawVertLine(int x,int startRow,int num)__critical
	{
		unsigned char i;
		
		for(i=0;i<num;i++){
			
			glcd_setPixel(x,startRow);
			startRow++;
		
		
//			if(startRow==64){
//				break;
//			}

		}
	}
	
	
	
	
	void clrVertLine(int x,int startRow,int num)
	{
		unsigned char i;
		
		for(i=0;i<num;i++){
			
			glcd_clrPixel(x,startRow);
			startRow++;
		
//			if(startRow==64){
//				break;
//			}

		}
	}
	
	void clrHorzLine(int y,int startCol,int num)
	{
		unsigned char i;
		
		for(i=0;i<num;i++){
			
			glcd_clrPixel(startCol,y);
			startCol++;
		
//			if(startCol==128){
//				break;
//			}

		}
	}
	
	
void drawChar(int col,int page,char val)
{
int i;
int seek;
char currentData; 


/*5x3 font*/

char font[480]=
	{0x00, 0x00, 0x00,// (space)
	 0x00, 0x5F, 0x00,// !
	0x00, 0x07, 0x00,// "
	0x14, 0x7F, 0x14,// #
	0x24, 0x2A, 0x7F,// $
	0x23, 0x13, 0x08,// %
	0x36, 0x49, 0x55,// &
	0x00, 0x05, 0x03,// '
	0x00, 0x1C, 0x22,// (
	0x00, 0x41, 0x22,// )
	0x08, 0x2A, 0x1C,// *
	0x20, 0x70, 0x20,// +
	0x00, 0x50, 0x30,// ,
	0x20, 0x20, 0x20, // -
	0x00, 0x60, 0x60,// .
	0x20, 0x10, 0x08,// /
	0xF8, 0x88, 0xF8,// 0
	0x90, 0xF8, 0x80, // 1
	0xE8, 0xA8, 0xB8,// 2
	0xA8, 0xA8, 0xF8,// 3
	0x78, 0x40, 0xE0,// 4
	0xB8, 0xA8, 0xE8,// 5
	0xF8, 0xA8, 0xE8,// 6
	0x18, 0x08, 0xF8,// 7
	0xF8, 0xA8, 0xF8,// 8
	0xB8, 0xA8, 0xF8, // 9
	0x00, 0x50, 0x00,  // :
	0x00, 0x56, 0x36,// ;
	0x00, 0x08, 0x14,// <
	0x50, 0x50, 0x50,// =
	0x41, 0x22, 0x14,// >
	0x02, 0x01, 0x51,// ?
	0x32, 0x49, 0x79,// @
	0xF8, 0x28, 0xF8,// A
	0xF8, 0xA8, 0x70,// B
	0xF8, 0x88, 0x88,// C
	0xF8, 0x88, 0x70, // D
	0xF8, 0xA8, 0xA8,// E
	0xF8, 0x28, 0x28,// F
	0xF8, 0x88, 0xC8,// G
	0xF8, 0x20, 0xF8, // H
	0x88, 0xF8, 0x88, // I
	0x88, 0xF8, 0x88,// J
	0xF8, 0x20, 0x88, // K
	0xF8, 0x80, 0x80,// L
	0xF8, 0x10, 0xF8,// M
	0xF8, 0x10, 0xF8,// N
	0xF8, 0x88, 0xF8,// O
	0xF8, 0x28, 0x38,// P
	0x3E, 0x41, 0x51,// Q
	0xF8, 0x68, 0xB8, // R
    0xB8, 0xA8, 0xE8,// S
	0x08, 0xF8, 0x08,// T
	0xF8, 0x80, 0xF8,// U
	0x78, 0x80, 0x78,// V
	0x7F, 0x20, 0x18,// W
	0x63, 0x14, 0x08,// X
	0x03, 0x04, 0x78,// Y
	0x61, 0x51, 0x49,// Z
	0x00, 0x00, 0x7F,// [
	0x02, 0x04, 0x08,// "\"
	0x41, 0x41, 0x7F,// ]
	0x04, 0x02, 0x01,// ^
	0x40, 0x40, 0x40,// _
	0x00, 0x01, 0x02,// `
	0x78, 0x80, 0x78,// a
	0xF8, 0xA0, 0xE0,// b
	0xF8, 0xA0, 0xE0,// c
	0xF0, 0x90, 0xF8,// d
	0xF8, 0xA8, 0xB8,// e
	0x20, 0xF8, 0x28,// f
	0x08, 0x14, 0x54,// g
	0x7F, 0x08, 0x04,// h
	0x00, 0x44, 0x7D,// i
	0x20, 0x40, 0x44,// j
	0x00, 0x7F, 0x10,// k
	0x00, 0x41, 0x7F,// l
	0x7C, 0x04, 0x18,// m
	0x7C, 0x08, 0x04,// n
	0x38, 0x44, 0x44,// o
	0x7C, 0x14, 0x14,// p
	0x08, 0x14, 0x14,// q
	0x7C, 0x08, 0x04,// r
	0x48, 0x54, 0x54,// s
	0x04, 0x3F, 0x44,// t
	0x3C, 0x40, 0x40,// u
	0x1C, 0x20, 0x40,// v
	0x3C, 0x40, 0x30,// w
	0x44, 0x28, 0x10,// x
	0x0C, 0x50, 0x50,// y
	0x44, 0x64, 0x54,// z
	0x44, 0x64, 0x54,//{
	0x00, 0xF8, 0x00 };//|

			
			
seek=(val-' ')*characterWidth;			
//printf("seek %d",seek);
for(i=0;i<characterWidth;i++)
{
			
			
			if(col<(MAX_COL_PIXEL/2))
			{
			/*left side of screen*/
			currentData=gLCD_read(1); //dummy read, mention in the report
			currentData=gLCD_read(1);
			}
			else
			{
			/*right side of screen*/
			currentData=gLCD_read(2); //dummy read, mention in the report
			currentData=gLCD_read(2);
			}
			
			currentData|=font[seek+i];
			glcdWrByte(col,page,currentData);
			col=col+1;


}

}


/*each alphabet will take 5x3  pixels*/
void drawString(char * val,int page,int col)__critical
{
int i;
int space;

glcd_gotoaddr(col,page);
space=0;
for(i=0;i<strlen(val);i++)
{
	 drawChar(col+space,page,val[i]);
	 space=space+4;  //gives space of 1 pixels between two characters 
}
	
}

/*clear number of characters*/
void clrString(int page,int col,int numberofChar)__critical
{
	int i;
	int j;


	for(i=0;i<numberofChar;i++)
	{
		for(j=0;j<characterWidth+1;j++) //clear width of character plus 1 spacing given in drawstring
		{
			clrBlock(col,page);
			col++;
		}
	}
}
	

/*remember first write text!!!!, then lines since text doest not implement dataread(NOT REQUIRED NOW!!)*/
void drawGraph(int mode)
{
if(mode==1)
{
drawString("31",3,0);
drawString(" 0",6,0);
//drawString("f (GHz)",7,110);
drawHorzLine(56,8,80); /*horizontal line*/
drawVertLine(8,25,31);	/*vertical line*/
drawBLine(0,63,8,56);

/**bottom box**********/
drawVertLine(88,49,15);	/*vertical line*/
drawHorzLine(49,88,40); /*horizontal line*/
}
else
{
	
	
}



}

void drawGraphMarkers(int mode)
{
	
	
	if (mode==1)
	{
		drawString("1",7,x_graphStart+9); //channel 1
		drawString("2",7,x_graphStart+14); //channel 2
		drawString("3",7,x_graphStart+19); //channel 3
		drawString("4",7,x_graphStart+24); //channel 4
		drawString("5",7,x_graphStart+29); //channel 5
		drawString("6",7,x_graphStart+34); //channel 6
		drawString("7",7,x_graphStart+39); //channel 7
		drawString("8",7,x_graphStart+44); //channel 8
		drawString("9",7,x_graphStart+49); //channel 9
		drawString("A",7,x_graphStart+54); //channel 10
		drawString("B",7,x_graphStart+59); //channel 11
			
		drawVertLine(x_graphStart+10,maxY+1,1); //small marker channel 1
		drawVertLine(x_graphStart+15,maxY+1,1); //small marker channel 2
		drawVertLine(x_graphStart+20,maxY+1,1); //small marker channel 3
		drawVertLine(x_graphStart+25,maxY+1,1); //small marker channel 4
		drawVertLine(x_graphStart+30,maxY+1,1); //small marker channel 5
		drawVertLine(x_graphStart+35,maxY+1,1); //small marker channel 6
		drawVertLine(x_graphStart+40,maxY+1,1); //small marker channel 7
		drawVertLine(x_graphStart+45,maxY+1,1); //small marker channel 8
		drawVertLine(x_graphStart+45,maxY+1,1); //small marker channel 8
		drawVertLine(x_graphStart+50,maxY+1,1); //small marker channel 9
		drawVertLine(x_graphStart+55,maxY+1,1); //small marker channel 10
		drawVertLine(x_graphStart+60,maxY+1,1); //small marker channel 11
			
	}
	
}



/*returns absolute difference between two numbers*/
int getAbsValue(int val1,int val2)
{
	unsigned char ans;
	
	if(val1>val2)
	{
		ans=val1-val2;
	}
	else
	{
		ans=val2-val1;
	}
	return ans;
}

int channelNumber(int centerFreq)  /*returns channel number in char form*/
{
	unsigned char number;
	
	if(centerFreq==12)
	{
		number=1;
	}
	
	if(centerFreq==17)
	{
		number=2;
	}
	
	if(centerFreq==22)
	{
		number=3;
	}
	
	if(centerFreq==27)
	{
		number=4;
	}
	
	if(centerFreq==32)
	{
		number=5;
	}
	
	if(centerFreq==37)
	{
		number=6;
	}
	
	if(centerFreq==42)
	{
		number=7;
	}
	
	if(centerFreq==47)
	{
		number=8;
	}
	
	if(centerFreq==52)
	{
		number=9;
	}
	
	if(centerFreq==57)
	{
		number=10;
	}
	
	if(centerFreq==62)
	{
		number=11;
	}
	
	return number;
	
}

